home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / netz / magplip / source / server.c < prev    next >
C/C++ Source or Header  |  1995-08-20  |  28KB  |  944 lines

  1. /*
  2. ** $VER: server.c 1.9 (20 Aug 1995)
  3. **
  4. ** magplip.device - Parallel Line Internet Protocol
  5. **
  6. ** Original code written by Oliver Wagner and Michael Balzer.
  7. **
  8. ** This version has been completely reworked by Marius Gröger, introducing
  9. ** slight protocol changes. The new source is a lot better organized and
  10. ** maintainable.
  11. **
  12. ** Additional changes and code cleanup by Jan Kratochvil and Martin Mares.
  13. ** The new source is significantly faster and yet better maintainable.
  14. **
  15. ** (C) Copyright 1993-1994 Oliver Wagner & Michael Balzer
  16. ** (C) Copyright 1995 Marius Gröger
  17. ** (C) Copyright 1995 Jan Kratochvil & Martin Mares
  18. **     All Rights Reserved
  19. **
  20. ** $HISTORY:
  21. **
  22. ** 20 Aug 1995 : 001.009 :  support for ASM xfer routines
  23. **                          removed obsolete CIA macros (mag/jk/mm)
  24. ** 29 Jul 1995 : 001.008 :  support for arbitration delay
  25. **                          symmetrical handling
  26. ** 26 Apr 1995 : 001.007 :  _very_ nasty bug would miss packets and get
  27. **                          the driver totally irritated
  28. ** 25 Apr 1995 : 001.006 :  now compiles with ANSI and STRICT
  29. **                          fixed bug with resource allocation
  30. ** 08 Mar 1995 : 001.005 :  write req. are now handled by device.c
  31. ** 06 Mar 1995 : 001.004 :  collision delay added
  32. ** 06 Mar 1995 : 001.003 :  hardware transmission errors are no longer retried
  33. **                          because this is any upper layers job
  34. ** 04 Mar 1995 : 001.002 :  event tracking *much* more conform to SANA-2
  35. ** 18 Feb 1995 : 001.001 :  startup now a bit nicer
  36. **                          using BASEPTR
  37. ** 12 Feb 1995 : 001.000 :  reworked original
  38. */
  39.  
  40. #define DEBUG 0
  41.  
  42. /*F*/ /* includes */
  43. #ifndef CLIB_EXEC_PROTOS_H
  44. #include <clib/exec_protos.h>
  45. #include <pragmas/exec_sysbase_pragmas.h>
  46. #endif
  47. #ifndef CLIB_DOS_PROTOS_H
  48. #include <clib/dos_protos.h>
  49. #include <pragmas/dos_pragmas.h>
  50. #endif
  51. #ifndef CLIB_CIA_PROTOS_H
  52. #include <clib/cia_protos.h>
  53. #include <pragmas/cia_pragmas.h>
  54. #endif
  55. #ifndef CLIB_MISC_PROTOS_H
  56. #include <clib/misc_protos.h>
  57. #include <pragmas/misc_pragmas.h>
  58. #endif
  59. #ifndef CLIB_TIME_PROTOS_H
  60. #include <clib/timer_protos.h>
  61. #include <pragmas/timer_pragmas.h>
  62. #endif
  63. #ifndef CLIB_UTILITY_PROTOS_H
  64. #include <clib/utility_protos.h>
  65. #include <pragmas/utility_pragmas.h>
  66. #endif
  67.  
  68. #ifndef EXEC_MEMORY_H
  69. #include <exec/memory.h>
  70. #endif
  71. #ifndef EXEC_INTERRUPTS_H
  72. #include <exec/interrupts.h>
  73. #endif
  74. #ifndef EXEC_DEVICES_H
  75. #include <exec/devices.h>
  76. #endif
  77. #ifndef EXEC_IO_H
  78. #include <exec/io.h>
  79. #endif
  80.  
  81. #ifndef DEVICES_SANA2_H
  82. #include <devices/sana2.h>
  83. #endif
  84.  
  85. #ifndef HARDWARE_CIA_H
  86. #include <hardware/cia.h>
  87. #endif
  88.  
  89. #ifndef RESOURCES_MISC_H
  90. #include <resources/misc.h>
  91. #endif
  92.  
  93. #ifndef _STRING_H
  94. #include <string.h>
  95. #endif
  96.  
  97. #ifndef __MAGPLIP_H
  98. #include "magplip.h"
  99. #endif
  100. #ifndef __DEBUG_H
  101. #include "debug.h"
  102. #endif
  103. /*E*/
  104.  
  105. /*F*/ /* defines, types and enums */
  106.  
  107.    /*
  108.    ** return codes for arbitratedwrite()
  109.    */
  110. typedef enum { AW_OK, AW_ABORTED, AW_BUFFER_ERROR, AW_ERROR } AW_RESULT;
  111.  
  112. /*E*/
  113. /*F*/ /* imports */
  114. extern VOID dotracktype(BASEPTR, ULONG type, ULONG ps, ULONG pr, ULONG bs, ULONG br, ULONG pd);
  115. extern VOID DevTermIO(BASEPTR, struct IOSana2Req *ios2);
  116. extern USHORT ASM CRC16(REG(a0) UBYTE *, REG(d0) SHORT);
  117. extern BOOL ASM hwsend(REG(a0) BASEPTR);
  118. extern BOOL ASM hwrecv(REG(a0) BASEPTR);
  119. extern VOID ASM interrupt(REG(a1) BASEPTR);
  120.  
  121. extern FAR volatile struct CIA ciaa,ciab;
  122. /*E*/
  123. /*F*/ /* exports */
  124. extern VOID __saveds ServerTask(VOID);
  125. /*E*/
  126. /*F*/ /* statics */
  127. static struct PLIPBase *startup(void);
  128. static REGARGS VOID DoEvent(BASEPTR, long event);
  129. static VOID readargs(BASEPTR);
  130. static BOOL init(BASEPTR);
  131. static BOOL hwattach(BASEPTR);
  132. static VOID hwdetach(BASEPTR);
  133. static REGARGS BOOL goonline(BASEPTR);
  134. static REGARGS VOID gooffline(BASEPTR);
  135. static REGARGS AW_RESULT arbitratedwrite(BASEPTR, struct IOSana2Req *ios2);
  136. static REGARGS VOID dowritereqs(BASEPTR);
  137. static REGARGS VOID doreadreqs(BASEPTR);
  138. static REGARGS VOID dos2reqs(BASEPTR);
  139. /*E*/
  140.  
  141. /*F*/ /* CIA access macros & functions */
  142.  
  143. #define CLEARINT        SetICR(CIAABase, CIAICRF_FLG)
  144. #define DISABLEINT      AbleICR(CIAABase, CIAICRF_FLG)
  145. #define ENABLEINT       AbleICR(CIAABase, CIAICRF_FLG | CIAICRF_SETCLR)
  146.  
  147. #define SETCIAOUTPUT    ciaa.ciaddrb = 0xFF
  148. #define SETCIAINPUT     ciaa.ciaddrb = 0x00
  149. #define PARINIT(b)      SETCIAINPUT;                                       \
  150.                         ciab.ciaddra &= ~((b)->pb_HandshakeMask[HS_LINE]); \
  151.                         ciab.ciaddra |= (b)->pb_HandshakeMask[HS_REQUEST]
  152.  
  153. #define TESTLINE(b)     (ciab.ciapra & (b)->pb_HandshakeMask[HS_LINE])
  154. #define SETREQUEST(b)   ciab.ciapra |= (b)->pb_HandshakeMask[HS_REQUEST]
  155. #define CLEARREQUEST(b) ciab.ciapra &= ~((b)->pb_HandshakeMask[HS_REQUEST])
  156.  
  157. /*E*/
  158.  
  159.    /*
  160.    ** functions to gain hardware, initialise communication
  161.    ** and to release hardware
  162.    */
  163. /*F*/ static BOOL hwattach(BASEPTR)
  164. {
  165.    BOOL rc = FALSE;
  166.  
  167.    d(("entered\n"));
  168.  
  169.    if (MiscBase = OpenResource("misc.resource"))
  170.    {
  171.       if (CIAABase = OpenResource("ciaa.resource"))
  172.       {
  173.          CiaBase = CIAABase;
  174.  
  175.          d(("ciabase is %lx\n",CiaBase));
  176.  
  177.          /* obtain exclusive access to the parallel hardware */
  178.          if (!AllocMiscResource(MR_PARALLELPORT, pb->pb_DevNode.lib_Node.ln_Name))
  179.          {
  180.             pb->pb_AllocFlags |= 1;
  181.             if (!AllocMiscResource(MR_PARALLELBITS, pb->pb_DevNode.lib_Node.ln_Name))
  182.             {
  183.                pb->pb_AllocFlags |= 2;
  184.  
  185.                /* Add our interrupt to handle CIAICRB_FLG.
  186.                ** This is also cia.resource means of granting exclusive
  187.                ** access to the related registers in the CIAs.
  188.                */
  189.                pb->pb_Interrupt.is_Node.ln_Type = NT_INTERRUPT;
  190.                pb->pb_Interrupt.is_Node.ln_Pri  = 127;
  191.                pb->pb_Interrupt.is_Node.ln_Name = SERVERTASKNAME;
  192.                pb->pb_Interrupt.is_Data         = (APTR)pb;
  193.                pb->pb_Interrupt.is_Code         = (VOID (*)())&interrupt;
  194.  
  195.                /* We must Disable() bcos there could be an interrupt already
  196.                ** waiting for us. We may, however, not Able/SetICR() before
  197.                ** we have access!
  198.                */
  199.                Disable();
  200.                if (!AddICRVector(CIAABase, CIAICRB_FLG, &pb->pb_Interrupt))
  201.                {
  202.                   DISABLEINT;                       /* this is what I meant */
  203.                   rc = TRUE;
  204.                }
  205.                Enable();
  206.  
  207.                if (rc)
  208.                {
  209.                   pb->pb_AllocFlags |= 4;
  210.                   PARINIT(pb);    /* cia to input, handshake in/out setting */
  211.                   CLEARREQUEST(pb);                /* setup handshake lines */
  212.                   CLEARINT;                         /* clear this interrupt */
  213.                   ENABLEINT;                            /* allow interrupts */
  214.                }
  215.  
  216.             }
  217.             else
  218.                d(("no parallelbits\n"));
  219.          }
  220.          else
  221.             d(("no parallelport\n"));
  222.       }
  223.       else
  224.          d(("no misc resource\n"));
  225.    }
  226.    else
  227.       d(("no misc resource\n"));
  228.  
  229.    return rc;
  230. }
  231. /*E*/
  232. /*F*/ static VOID hwdetach(BASEPTR)
  233. {
  234.    if (pb->pb_AllocFlags & 4)
  235.    {
  236.       DISABLEINT;
  237.       CLEARINT;
  238.       RemICRVector(CIAABase, CIAICRB_FLG, &pb->pb_Interrupt);
  239.    }
  240.  
  241.    if (pb->pb_AllocFlags & 2) FreeMiscResource(MR_PARALLELBITS);
  242.  
  243.    if (pb->pb_AllocFlags & 1) FreeMiscResource(MR_PARALLELPORT);
  244.  
  245.    pb->pb_AllocFlags = 0;
  246. }
  247. /*E*/
  248.  
  249.    /*
  250.    ** functions to go online/offline
  251.    */
  252. /*F*/ static REGARGS VOID rejectpackets(BASEPTR)
  253. {
  254.    struct IOSana2Req *ios2;
  255.  
  256.    ObtainSemaphore(&pb->pb_WriteListSem);
  257.    while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_WriteList))
  258.    {
  259.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  260.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  261.       DevTermIO(pb,ios2);
  262.    }
  263.    ReleaseSemaphore(&pb->pb_WriteListSem);
  264.  
  265.    ObtainSemaphore(&pb->pb_ReadListSem);
  266.    while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadList))
  267.    {
  268.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  269.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  270.       DevTermIO(pb,ios2);
  271.    }
  272.    ReleaseSemaphore(&pb->pb_ReadListSem);
  273.  
  274.    ObtainSemaphore(&pb->pb_ReadOrphanListSem);
  275.    while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList))
  276.    {
  277.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  278.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  279.       DevTermIO(pb,ios2);
  280.    }
  281.    ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
  282. }
  283. /*E*/
  284. /*F*/ static REGARGS BOOL goonline(BASEPTR)
  285. {
  286.    BOOL rc = FALSE;
  287.  
  288.    d(("trying to go online\n"));
  289.  
  290.    if (pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED))
  291.    {
  292.       if (!hwattach(pb))
  293.       {
  294.          d(("error going online\n"));
  295.       }
  296.       else
  297.       {
  298.          GetSysTime(&pb->pb_DevStats.LastStart);
  299.          pb->pb_Flags &= ~(PLIPF_OFFLINE | PLIPF_NOTCONFIGURED);
  300.          DoEvent(pb, S2EVENT_ONLINE);
  301.          rc = TRUE;
  302.          d(("i'm now online!\n"));
  303.       }
  304.    }
  305.  
  306.    return rc;
  307. }
  308. /*E*/
  309. /*F*/ static REGARGS VOID gooffline(BASEPTR)
  310. {
  311.    if (!(pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED)))
  312.    {
  313.       hwdetach(pb);
  314.  
  315.       pb->pb_Flags |= PLIPF_OFFLINE;
  316.  
  317.       DoEvent(pb, S2EVENT_OFFLINE);
  318.    }
  319.    d(("ok!\n"));
  320. }
  321. /*E*/
  322.  
  323.    /*
  324.    ** SANA-2 Event management
  325.    */
  326. /*F*/ static REGARGS VOID DoEvent(BASEPTR, long event)
  327. {
  328.    struct IOSana2Req *ior, *ior2;
  329.  
  330.    d(("event is %lx\n",event));
  331.  
  332.    ObtainSemaphore(&pb->pb_EventListSem );
  333.    
  334.    for(ior = (struct IOSana2Req *) pb->pb_EventList.lh_Head;
  335.        ior2 = (struct IOSana2Req *) ior->ios2_Req.io_Message.mn_Node.ln_Succ;
  336.        ior = ior2 )
  337.    {
  338.       if (ior->ios2_WireError & event)
  339.       {
  340.          Remove((struct Node*)ior);
  341.          DevTermIO(pb, ior);
  342.       }
  343.    }
  344.    
  345.    ReleaseSemaphore(&pb->pb_EventListSem );
  346. }
  347. /*E*/
  348.  
  349.    /*
  350.    ** writing packets
  351.    */
  352. /*F*/ static REGARGS AW_RESULT arbitratedwrite(BASEPTR, struct IOSana2Req *ios2)
  353. {
  354.    BOOL having_line;
  355.    AW_RESULT rc;
  356.  
  357.    /*
  358.    ** Arbitration
  359.    ** ===========================================================
  360.    **
  361.    ** Pseudo code of the arbitration:
  362.    **
  363.    **  if LINE is high (other side is ready to receive) then
  364.    **     set REQUEST high (tell the other side we're ready to send)
  365.    **     if LINE is high (other side is still ready to receive) then
  366.    **        we have the line, do transfer
  367.    **     reset REQUEST to low (tell other side we're ready to receive)
  368.    **
  369.    **    AW_OK             if we could transmit all the data correctly
  370.    **    AW_BUFF_ERROR     if the BufferManagement callback failed
  371.    **    AW_ERROR          if we got the line, but the actual transfer
  372.    **                      failed, perhaps due to a timeout
  373.    **    AW_ABORT          if we couldn't get the line
  374.    */
  375.  
  376.    having_line = FALSE;
  377.  
  378.    if (!TESTLINE(pb))                               /* is the line free ? */
  379.    {
  380.       SETREQUEST(pb);                     /* indicate our request to send */
  381.       
  382.       if (pb->pb_ArbitrationDelay > 0)
  383.       {
  384.          pb->pb_TimeReq.tr_time.tv_secs    = 0;
  385.          pb->pb_TimeReq.tr_time.tv_micro   = pb->pb_ArbitrationDelay;
  386.          pb->pb_TimeReq.tr_node.io_Command = TR_ADDREQUEST;
  387.          DoIO((struct IORequest*)&pb->pb_TimeReq);
  388.       }
  389.  
  390.       if (!TESTLINE(pb))                      /* is the line still free ? */
  391.          having_line = TRUE;
  392.       else
  393.       {
  394.          if (!(pb->pb_Flags & PLIPF_RECEIVING))
  395.             CLEARREQUEST(pb);                         /* reset line state */
  396.          d2(("couldn't get the line-1\n"));
  397.       }
  398.    }
  399.    else d2(("couldn't get the line-2\n"));
  400.  
  401.    if (having_line)
  402.    {
  403.       struct BufferManagement *bm;
  404.  
  405.       if (!(pb->pb_Flags & PLIPF_RECEIVING))
  406.       {
  407.          d(("having line for: typ %08lx, size %ld\n",ios2->ios2_PacketType,
  408.                                                       ios2->ios2_DataLength));
  409.  
  410.          pb->pb_SendFrame.pf_Type = ios2->ios2_PacketType;
  411.          pb->pb_SendFrame.pf_Size = ios2->ios2_DataLength + PKTFRAMESIZE_2;
  412.  
  413.          bm = (struct BufferManagement *)ios2->ios2_BufferManagement;
  414.  
  415.          if (!(*bm->bm_CopyFromBuffer)((UBYTE*)pb->pb_SendFrame.pf_Data,
  416.                                      ios2->ios2_Data, ios2->ios2_DataLength))
  417.          {
  418.             rc = AW_BUFFER_ERROR;
  419.             CLEARREQUEST(pb);                         /* reset line state */
  420.          }
  421.          else
  422.             rc = hwsend(pb) ? AW_OK : AW_ERROR;
  423.       }
  424.       else
  425.       {
  426.          d4(("arbitration error!\n"));
  427.          rc = AW_ABORTED;
  428.       }
  429.    }
  430.    else
  431.       rc = AW_ABORTED;
  432.  
  433.    return rc;
  434. }
  435. /*E*/
  436. /*F*/ static REGARGS VOID dowritereqs(BASEPTR)
  437. {
  438.    struct IOSana2Req *currentwrite, *nextwrite;
  439.    AW_RESULT code;
  440.  
  441.    ObtainSemaphore(&pb->pb_WriteListSem);
  442.  
  443.    for(currentwrite = (struct IOSana2Req *)pb->pb_WriteList.lh_Head;
  444.        nextwrite = (struct IOSana2Req *) currentwrite->ios2_Req.io_Message.mn_Node.ln_Succ;
  445.        currentwrite = nextwrite )
  446.    {
  447.       if (pb->pb_Flags & PLIPF_RECEIVING)
  448.       {
  449.          d(("incoming data!"));
  450.          break;
  451.       }
  452.  
  453.       code = arbitratedwrite(pb, currentwrite);
  454.  
  455.       if (code == AW_ABORTED)                         /* arbitration failed */
  456.       {
  457.          pb->pb_Flags |= PLIPF_COLLISION;
  458.          d(("couldn't get the line, trying again later\n"));
  459.          if ((currentwrite->ios2_Req.io_Error++) > pb->pb_Retries)
  460.          {
  461.             currentwrite->ios2_Req.io_Error = S2ERR_TX_FAILURE;
  462.             currentwrite->ios2_WireError = S2WERR_TOO_MANY_RETIRES;
  463.             Remove((struct Node*)currentwrite);
  464.             DevTermIO(pb, currentwrite);
  465.          }
  466.          break;
  467.       }
  468.       else if (code == AW_BUFFER_ERROR)  /* BufferManagement callback error */
  469.       {
  470.          d(("buffer error\n"));
  471.          DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
  472.          currentwrite->ios2_Req.io_Error = S2ERR_SOFTWARE;
  473.          currentwrite->ios2_WireError = S2WERR_BUFF_ERROR;
  474.          Remove((struct Node*)currentwrite);
  475.          DevTermIO(pb, currentwrite);
  476.       }
  477.       else if (code == AW_ERROR)
  478.       {
  479.          /*
  480.          ** this is a real line error, upper levels (e.g. Internet TCP) have
  481.          ** to care for reliability!
  482.          */
  483.          d(("error transmitting packet\n"));
  484.          DoEvent(pb, S2EVENT_ERROR | S2EVENT_TX | S2EVENT_HARDWARE);
  485.          currentwrite->ios2_Req.io_Error = S2ERR_TX_FAILURE;
  486.          currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR;
  487.          Remove((struct Node*)currentwrite);
  488.          DevTermIO(pb, currentwrite);
  489.       }
  490.       else /*if (code == AW_OK)*/                             /* well done! */
  491.       {
  492.          d(("packet transmitted successfully\n"));
  493.          pb->pb_DevStats.PacketsSent++;
  494.          dotracktype(pb, pb->pb_SendFrame.pf_Type, 1, 0, currentwrite->ios2_DataLength, 0, 0);
  495.          currentwrite->ios2_Req.io_Error = S2ERR_NO_ERROR;
  496.          currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR;
  497.          Remove((struct Node*)currentwrite);
  498.          DevTermIO(pb, currentwrite);
  499.       }
  500.    }
  501.  
  502.    ReleaseSemaphore(&pb->pb_WriteListSem);
  503. }
  504. /*E*/
  505.  
  506.    /*
  507.    ** reading packets
  508.    */
  509. /*F*/ static REGARGS VOID doreadreqs(BASEPTR)
  510. {
  511.    LONG datasize;
  512.    struct IOSana2Req *got;
  513.    ULONG pkttyp;
  514.    struct BufferManagement *bm;
  515.  
  516.    if (hwrecv(pb))
  517.    {
  518.       pb->pb_DevStats.PacketsReceived++;
  519.  
  520.       datasize = pb->pb_ReceiveFrame.pf_Size - PKTFRAMESIZE_2;
  521.  
  522.       dotracktype(pb, pkttyp = pb->pb_ReceiveFrame.pf_Type, 0, 1, 0, datasize, 0);
  523.  
  524.       d(("packet %08lx, size %ld received\n",pkttyp,datasize));
  525.  
  526.       ObtainSemaphore(&pb->pb_ReadListSem);
  527.  
  528.       for(got = (struct IOSana2Req *)pb->pb_ReadList.lh_Head;
  529.           got->ios2_Req.io_Message.mn_Node.ln_Succ;
  530.           got = (struct IOSana2Req *)got->ios2_Req.io_Message.mn_Node.ln_Succ )
  531.       {
  532.          if (got->ios2_PacketType == pkttyp )
  533.          {
  534.             Remove((struct Node*)got);
  535.  
  536.             bm = (struct BufferManagement *)got->ios2_BufferManagement;
  537.  
  538.             if (!(*bm->bm_CopyToBuffer)(got->ios2_Data, (UBYTE*)pb->pb_ReceiveFrame.pf_Data, datasize))
  539.             {
  540.                d(("CopyToBuffer: error\n"));
  541.                got->ios2_Req.io_Error = S2ERR_SOFTWARE;
  542.                got->ios2_WireError = S2WERR_BUFF_ERROR;
  543.                DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
  544.             }
  545.             else
  546.             {
  547.                got->ios2_Req.io_Error = got->ios2_WireError = 0;
  548.             }
  549.  
  550.             got->ios2_Req.io_Flags = 0;
  551.             got->ios2_SrcAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ?  0     : (1<<7);
  552.             got->ios2_DstAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ? (1<<7) :  0    ;
  553.             got->ios2_DataLength = datasize;
  554.  
  555.             d(("packet received, satisfying S2Request\n"));
  556.             DevTermIO(pb, got);
  557.             got = NULL;
  558.             break;
  559.          }
  560.       }
  561.  
  562.       ReleaseSemaphore(&pb->pb_ReadListSem);
  563.    }
  564.    else
  565.    {
  566.       DoEvent(pb, S2EVENT_HARDWARE | S2EVENT_ERROR | S2EVENT_RX);
  567.       
  568.       got = NULL;
  569.       pb->pb_DevStats.BadData++;
  570.    }
  571.    
  572.    if (got)
  573.    {
  574.       d(("unknown packet\n"));
  575.  
  576.       pb->pb_DevStats.UnknownTypesReceived++;
  577.       
  578.       ObtainSemaphore(&pb->pb_ReadOrphanListSem);
  579.       got = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList);
  580.       ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
  581.  
  582.       if (got)
  583.       {
  584.          bm = (struct BufferManagement *)got->ios2_BufferManagement;
  585.          if (!(*bm->bm_CopyToBuffer)(got->ios2_Data, (UBYTE*)pb->pb_ReceiveFrame.pf_Data, datasize))
  586.          {
  587.             got->ios2_Req.io_Error = S2ERR_SOFTWARE;
  588.             got->ios2_WireError = S2WERR_BUFF_ERROR;
  589.          }
  590.          else
  591.          {
  592.             got->ios2_Req.io_Error = got->ios2_WireError = 0;
  593.          }
  594.          
  595.          got->ios2_Req.io_Flags = 0;
  596.          got->ios2_SrcAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ?  0     : (1<<7);
  597.          got->ios2_DstAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ? (1<<7) :  0    ;
  598.          got->ios2_DataLength = datasize;
  599.  
  600.          d(("orphan read\n"));
  601.  
  602.          DevTermIO(pb, got);
  603.       }
  604.       else
  605.       {
  606.          dotracktype(pb, pkttyp, 0, 0, 0, 0, 1);
  607.          d(("packet thrown away...\n"));
  608.       }
  609.    }
  610. }
  611. /*E*/
  612.  
  613.    /*
  614.    ** 2nd level device command dispatcher (~SANA2IOF_QUICK)
  615.    */
  616. /*F*/ static REGARGS VOID dos2reqs(BASEPTR)
  617. {
  618.    struct IOSana2Req *ios2;
  619.  
  620.    /*
  621.    ** Every pending IO message will be GetMsg()'ed and processed. At the
  622.    ** end of the loop it will be DevTermIO()'ed back to the sender,
  623.    ** _but_only_if_ it is non-NULL. In such cases the message has been
  624.    ** put in a separate queue to be DevTermIO()'ed later (i.e. CMD_WRITEs
  625.    ** and similar stuff).
  626.    ** You find the same mimique in the 1st level dispatcher (device.c)
  627.    */
  628.    while(ios2 = (struct IOSana2Req *)GetMsg(pb->pb_ServerPort))
  629.    {
  630.       if (pb->pb_Flags & PLIPF_RECEIVING)
  631.       {
  632.          d(("incoming data!"));
  633.          break;
  634.       }
  635.  
  636.       d(("sana2req %ld from serverport\n", ios2->ios2_Req.io_Command));
  637.  
  638.       switch (ios2->ios2_Req.io_Command)
  639.       {
  640.          case S2_ONLINE:
  641.             if (!goonline(pb))
  642.             {
  643.                ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  644.                ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  645.             }
  646.          break;
  647.  
  648.          case S2_OFFLINE:
  649.             gooffline(pb);
  650.             rejectpackets(pb); /* reject all pending requests */
  651.          break;
  652.  
  653.          case S2_CONFIGINTERFACE:
  654.             if (pb->pb_Flags & PLIPF_NOTCONFIGURED)
  655.             {
  656.                ios2->ios2_SrcAddr[0] = (pb->pb_Flags & PLIPF_SIDEA) ? (1<<7) : 0;
  657.                
  658.                if (!goonline(pb))
  659.                {
  660.                   ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  661.                   ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  662.                }
  663.             }
  664.             else
  665.             {
  666.                ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  667.                ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
  668.             }
  669.          break;
  670.       }
  671.  
  672.       if (ios2) DevTermIO(pb,ios2);
  673.    }
  674. }
  675. /*E*/
  676.  
  677.    /*
  678.    ** startup,initialisation and termination functions
  679.    */
  680. /*F*/ static struct PLIPBase *startup(void)
  681. {
  682.    struct ServerStartup *ss;
  683.    struct Process *we;
  684.    struct PLIPBase *base;
  685.    LOCALSYSBASE;
  686.  
  687.    we = (struct Process*)FindTask(NULL);
  688.  
  689.    d(("waiting for startup msg...\n"));
  690.    WaitPort(&we->pr_MsgPort);
  691.    ss = (struct ServerStartup *)GetMsg(&we->pr_MsgPort);
  692.    base = ss->ss_PLIPBase;
  693.    d(("go startup msg at %lx, PLIPBase is %lx\n", ss, ss->ss_PLIPBase));
  694.    ReplyMsg((struct Message*)ss);
  695.  
  696.    return base;
  697. }
  698. /*E*/
  699. /*F*/ static VOID readargs(BASEPTR)
  700. {
  701.    struct RDArgs *rda;
  702.    struct PLIPConfig args = { 0 };
  703.    BPTR plipvar, oldinput;
  704.  
  705.    d(("entered\n"));
  706.  
  707.    if (plipvar = Open(CONFIGFILE, MODE_OLDFILE))
  708.    {
  709.       oldinput = SelectInput(plipvar);
  710.       
  711.       rda = ReadArgs(TEMPLATE , (LONG *)&args, NULL);
  712.       
  713.       if(rda)
  714.       {
  715.          if (args.timeout)
  716.             pb->pb_Timeout = *args.timeout;
  717.  
  718.          if (args.priority)
  719.             SetTaskPri((struct Task*)pb->pb_Server, *args.priority);
  720.  
  721.          if (args.mtu && (*args.mtu <= PLIP_MAXMTU))
  722.             pb->pb_MTU = *args.mtu;
  723.  
  724.          if (args.bps)
  725.             pb->pb_ReportBPS = *args.bps;
  726.  
  727.          if (args.retries &&  (*args.retries <= PLIP_MAXRETRIES))
  728.             pb->pb_Retries = *args.retries;
  729.  
  730.          if (args.sendcrc)
  731.             pb->pb_Flags |= PLIPF_SENDCRC;
  732.           else
  733.             pb->pb_Flags &= ~PLIPF_SENDCRC;
  734.  
  735.          if (args.collisiondelay)
  736.             pb->pb_CollisionDelay = *args.collisiondelay;
  737.          else
  738.             pb->pb_CollisionDelay = PLIP_DEFDELAY +
  739.                         (pb->pb_Flags & PLIPF_SIDEA) ? PLIP_DELAYDIFF : 0;
  740.  
  741.          if (args.arbitrationdelay)
  742.             pb->pb_ArbitrationDelay = *args.arbitrationdelay;
  743.          else
  744.             pb->pb_ArbitrationDelay = PLIP_DEFARBITRATIONDELAY;
  745.  
  746.          FreeArgs(rda);
  747.       }
  748.  
  749.       Close(SelectInput(oldinput));
  750.    }
  751.  
  752.    d(("timeout %ld, pri %ld, mtu %ld, bps %ld, retries %ld, flags %08lx, delay %ld\n",
  753.       pb->pb_Timeout, (LONG)pb->pb_Server->pr_Task.tc_Node.ln_Pri, pb->pb_MTU, pb->pb_ReportBPS, pb->pb_Retries,
  754.       pb->pb_Flags, pb->pb_CollisionDelay));
  755.  
  756.    d(("left\n"));
  757.  
  758. }
  759. /*E*/
  760. /*F*/ static BOOL init(BASEPTR)
  761. {
  762.    BOOL rc = FALSE;
  763.  
  764.    if ((pb->pb_IntSig = AllocSignal(-1)) != -1)
  765.    {
  766.       pb->pb_IntSigMask = 1L << pb->pb_IntSig;
  767.    
  768.       if (pb->pb_ServerPort = CreateMsgPort())
  769.       {
  770.          if (pb->pb_TimerPort = CreateMsgPort())
  771.          {
  772.             memset((VOID*)&pb->pb_TimeReq, 0, sizeof(pb->pb_TimeReq));
  773.             pb->pb_TimeReq.tr_node.io_Message.mn_ReplyPort = pb->pb_TimerPort;
  774.             if (!OpenDevice( "timer.device", UNIT_MICROHZ, (struct IORequest*)&pb->pb_TimeReq, 0 ))
  775.             {
  776.                TimerBase = (struct Library *)pb->pb_TimeReq.tr_node.io_Device;
  777.                readargs(pb);
  778.                rc = TRUE;
  779.             }
  780.             else
  781.             {
  782.                d(("couldn't open timer.device"));
  783.             }
  784.          }
  785.          else
  786.          {
  787.             d(("no timer port\n"));
  788.          }
  789.       }
  790.       else
  791.       {
  792.          d(("no server port\n"));
  793.       }
  794.    }
  795.    else
  796.    {
  797.       d(("no signal\n",rc));
  798.    }
  799.  
  800.    d(("left %ld\n",rc));
  801.  
  802.    return rc;
  803. }
  804. /*E*/
  805. /*F*/ static VOID cleanup(BASEPTR)
  806. {
  807.    struct BufferManagement *bm;
  808.  
  809.    gooffline(pb);
  810.  
  811.    while(bm = (struct BufferManagement *)RemHead((struct List *)&pb->pb_BufferManagement))
  812.       FreeVec(bm);
  813.  
  814.    if (TimerBase) CloseDevice((struct IORequest*)&pb->pb_TimeReq);
  815.    if (pb->pb_TimerPort) DeleteMsgPort(pb->pb_TimerPort);
  816.  
  817.    if (pb->pb_ServerPort) DeleteMsgPort(pb->pb_ServerPort);
  818.    if (pb->pb_IntSig != -1) FreeSignal(pb->pb_IntSig);
  819. }
  820. /*E*/
  821.  
  822.    /*
  823.    ** entry point, mainloop
  824.    */
  825. /*F*/ extern VOID SAVEDS ServerTask(void)
  826. {
  827.    BASEPTR;
  828.  
  829.    d(("server running\n"));
  830.  
  831.    if (pb = startup())
  832.    {
  833.       if (init(pb))
  834.       {
  835.          ULONG recv, portsigmask, timersigmask, wmask;
  836.          BOOL running, timerqueued = FALSE;
  837.  
  838.          portsigmask  = 1 << pb->pb_ServerPort->mp_SigBit;
  839.          timersigmask = 1 << pb->pb_TimerPort->mp_SigBit;
  840.       
  841.          wmask = SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_C | pb->pb_IntSigMask | portsigmask | timersigmask;
  842.  
  843.          for(running=TRUE;running;)
  844.          {
  845.             if (!(pb->pb_Flags & PLIPF_RECEIVING))
  846.                recv = Wait(wmask);
  847.             else
  848.                SetSignal(0, pb->pb_IntSigMask);
  849.  
  850.             /*if (recv & pb->pb_IntSigMask)*/
  851.             if (pb->pb_Flags & PLIPF_RECEIVING)
  852.             {
  853.                d(("received an interrupt\n"));
  854.                doreadreqs(pb);
  855.             }
  856.  
  857.             if (recv & portsigmask)
  858.             {
  859.                d(("SANA-II request(s)\n"));
  860.                dos2reqs(pb);
  861.             }
  862.  
  863.             if (recv & timersigmask)
  864.             {
  865.                /* pop message */
  866.                AbortIO((struct IORequest*)&pb->pb_TimeReq);
  867.                WaitIO((struct IORequest*)&pb->pb_TimeReq);
  868.                timerqueued = FALSE;
  869.                d(("timer wakeup\n"));
  870.             }
  871.  
  872.                /* try now to do write requests (if any pending) */
  873.             if (!timerqueued)
  874.             {
  875.                dowritereqs(pb);
  876.  
  877.                   /* don't let the other side wait too long! */
  878.                if (pb->pb_Flags & PLIPF_RECEIVING)
  879.                {
  880.                   d(("received an interrupt\n"));
  881.                   SetSignal(0, pb->pb_IntSigMask);
  882.                   doreadreqs(pb);
  883.                }
  884.  
  885.                /*
  886.                ** Possible a collision has occurred, which is indicated by a
  887.                ** special flag in PLIPBase.
  888.                **
  889.                ** Using timer.device we periodically will be waked up. This
  890.                ** allows us to delay write packets in cases when we cannot get
  891.                ** the line immediately.
  892.                **
  893.                ** If client and server are very close together, regarding the point
  894.                ** of performance, the same delay time could even force multiple
  895.                ** collisions (at least theoretical, I made no practical tests).
  896.                ** Probably a CSMA/CD-like random-timed delay would be ideal.
  897.                */
  898.                if (pb->pb_Flags & PLIPF_COLLISION)
  899.                {
  900.                   extern void KPrintF(char *,...);
  901.  
  902.                   pb->pb_Flags &= ~PLIPF_COLLISION;
  903.                   pb->pb_TimeReq.tr_time.tv_secs    = 0;
  904.                   pb->pb_TimeReq.tr_time.tv_micro   = pb->pb_CollisionDelay;
  905.                   pb->pb_TimeReq.tr_node.io_Command = TR_ADDREQUEST;
  906.                   /*KPrintF("waiting %ld/%ld\n", pb->pb_TimeReq.tr_time.tv_secs, pb->pb_TimeReq.tr_time.tv_micro);*/
  907.                   SendIO((struct IORequest*)&pb->pb_TimeReq);
  908.                   timerqueued = TRUE;
  909.                }
  910.             }
  911.  
  912.             if (recv & SIGBREAKF_CTRL_C)
  913.             {
  914.                d(("received break signal\n"));
  915.                running = FALSE;
  916.             }
  917.          }
  918.  
  919.          if (timerqueued)
  920.          {
  921.                /* finnish pending timer requests */
  922.             AbortIO((struct IORequest*)&pb->pb_TimeReq);
  923.             WaitIO((struct IORequest*)&pb->pb_TimeReq);
  924.          }
  925.       }
  926.       else
  927.          d(("init() failed\n"));
  928.  
  929.       d(("cleaning up\n"));
  930.       cleanup(pb);
  931.  
  932.             /* Exec will enable it's scheduler after we're dead. */
  933.       Forbid();
  934.             /* signal mother we're done */
  935.       if (pb->pb_ServerStoppedSigMask)
  936.          Signal(pb->pb_Task, pb->pb_ServerStoppedSigMask);
  937.       pb->pb_Flags |= PLIPF_SERVERSTOPPED;
  938.    }
  939.    else
  940.       d(("no startup packet\n"));
  941. }
  942. /*E*/
  943.  
  944.